#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@NAME          : rename.py
@TIME          : 2024/12/03 17:23:00
@AUTHOR        : chenlip
@VERSION       : 0.0.1
@DESCRIPTION   : 用于处理文件重命名，并将文件相关信息保存到 (data/mediares.db) 数据库
'''
# --------------------------引用--------------------------
import os, sqlite3, shutil, time, re
from data.inidata import initdb
# --------------------------引用--------------------------

# 获取当前文件的路径
_run_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
_db_path = os.path.join(_run_path, 'data')
if not os.path.exists(_db_path): os.mkdir(_db_path)

_mv_path = os.path.join(_run_path, 'mp4')

# 创建数据库文件及表
def create_db():
    '''
        创建数据库文件及表
        程序逻辑：
            - 如果数据库文件不存在，则创建数据库文件，并创建表，如果数据库文件存在，则连接到数据库
            fileinfo 文件信息表结构：
                - id: 自增id
                - path: minio文件路径
                - srcname: 原文件名（用于生成标签及文件介绍）
                - dstname: 新文件名
                - description: 文件介绍（可以为空，1024字符长度）
                - tags: 文件标签（可以为空，1024字符长度）
                - mcurl: minio文件存储位置（可以为空）
                - ctime: 创建时间
                - mtime: 修改时间
                - size: 文件大小
                - status: 文件状态（1-正常，0-删除...）
                - note: 备注
            filemeta 文件元数据表结构：
                - id: 自增id
                - fileinfoid: 文件信息表id
                - key: 元数据key
                - value: 元数据value
        :Args: 无
        :Return: conn
    '''
    _db_init = initdb(dbtype='sqlite', dbname=os.path.join(_db_path, 'mediares.db'))

    conn = sqlite3.connect(_db_init.dbpath)
    return conn

# 数据库连接
conn = create_db()

# 根据输入的sql语句查询数据
def query_data(sql:str):
    '''
        根据输入的sql语句查询数据
        :Args:
            - sql: 查询语句
        :Return:
            查询结果
    '''
    cursor = conn.cursor()
    cursor.execute(sql)
    res = cursor.fetchall()
    cursor.close()
    return res

# 插入一条数据，输入参数为字典
def insert_data(data:dict, meta:dict):
    '''
        插入一条数据，输入参数为字典
        :Args:
            - data: 数据字典，包含以下字段
                {
                    'path': 'mp4目录下的文件路径',
                    'srcname': '原文件名',
                    'dstname': '新文件名',
                    'description': '文件介绍',
                    'tags': '文件标签',
                    'mcurl': 'minio文件存储位置',
                    'ctime': '创建时间',
                    'mtime': '修改时间',
                    'size': '文件大小',
                    'status': '文件状态, 1-正常，0-删除...; 默认为1',
                    'note': '备注'
                }
            - meta: 元数据字典，包含以下字段
                {
                    'key1': 'value1',
                    'key2': 'value2',
                    ...
                }
        :Return:
            插入成功返回last_id，否则返回0
    '''
    last_id = 0
    try:
        cursor = conn.cursor()
        cursor.execute('''
            INSERT INTO fileinfo (path, srcname, dstname, description, tags, mcurl, ctime, mtime, size, status, note)
            VALUES (:path, :srcname, :dstname, :description, :tags, :mcurl, :ctime, :mtime, :size, :status, :note)
        ''', data)
        # 获取最后插入的id
        last_id = cursor.lastrowid
        # 插入元数据
        if meta is not None:
            for k, v in meta.items():
                cursor.execute('''
                    INSERT INTO filemeta (fileinfoid, key, value)
                    VALUES (:fileinfoid, :key, :value)
                ''', {'fileinfoid': last_id, 'key': k, 'value': v})
        
        conn.commit()
        cursor.close()
    except Exception as e:
        print(e)
        conn.rollback()  # 回滚事务
    
    return last_id

# 删除一条数据，输入参数为新文件名（同一个目录下面的文件不能重名）
def delete_data(dstname:str):
    '''
        删除一条数据，输入参数为新文件名（同一个目录下面的文件不能重名）
        :Args:
            - dstname: 新文件名，包含MP4目录下的文件路径，例如：'mp4/2024/12/03/17/23/00.mp4'
        :Return:
            删除成功返回True，否则返回False
    '''
    isok = False
    f_path = os.path.dirname(dstname)
    _fn = os.path.basename(dstname)
    try:
        cursor = conn.cursor()
        # 查询出要删除的文件信息ID
        _sql = 'SELECT id FROM fileinfo WHERE path = :path and dstname = :dstname'
        cursor.execute(_sql, {'path':f_path, 'dstname': dstname})
        res = cursor.fetchone()
        if res is None: 
            _id = res.get('id')
            cursor.execute('''DELETE FROM fileinfo WHERE id = :id''', {'id': _id})
            # 删除元数据
            cursor.execute('''DELETE FROM filemeta WHERE fileinfoid = :fileinfoid''', {'fileinfoid': _id})

            conn.commit()
            cursor.close()
            # 修改物理文件名称为 del_+dstname
            _file = os.path.join(_mv_path, dstname)
            if os.path.exists(_file): os.rename(_file, os.path.join(_mv_path, f_path, 'del_'+_fn))

        isok = True
    except Exception as e:
        print(e)
        conn.rollback()  # 回滚事务
    
    return isok

# 更新一条数据，输入参数为字典和ID
def update_data(dataid:int, data:dict):
    '''
        更新一条数据，输入参数为字典和ID，
        根据ID更新数据，数据字典可能包含以下字段中的一个或多个
        :Args:
            - data: 数据字典，可能包含以下字段中的一个或多个
                {
                    'path': 'mp4目录下的文件路径',
                    'srcname': '原文件名',
                    'dstname': '新文件名',
                    'description': '文件介绍',
                    'tags': '文件标签',
                    'mcurl': 'minio文件存储位置',
                    'ctime': '创建时间',
                    'mtime': '修改时间',
                    'size': '文件大小',
                    'status': '文件状态, 1-正常，0-删除...; 默认为1',
                    'note': '备注'
                }
        :Return:
            更新成功返回True，否则返回False
    '''
    isok = False
    try:
        cursor = conn.cursor()
        # 更新数据数据字典可能包含以下字段中的一个或多个， 例如：{'srcname': '原文件名', 'dstname': '新文件名'}
        # 根据data字典中的字段更新数据
        _sql = 'UPDATE fileinfo SET '
        _data = {}
        for k, v in data.items():
            _sql += k + ' = :' + k + ', '
            _data[k] = v
        _sql = _sql[:-2] + ' WHERE id = :id'
        _data['id'] = dataid

        cursor.execute(_sql, _data)
        conn.commit()
        cursor.close()
        isok = True
    except Exception as e:
        print(e)
        conn.rollback()  # 回滚事务

    return isok

# 更新一条文件信息的所有元数据，输入参数为文件信息ID和元数据字典
def update_meta(fileinfoid:int, meta:dict):
    '''
        更新一条元数据，输入参数为文件信息ID和元数据字典
        :Args:
            - fileinfoid: 文件信息ID
            - meta: 元数据字典，包含以下字段
                {
                    'key1': 'value1',
                    'key2': 'value2',
                    ...
                }
        :Return:
            更新成功返回True，否则返回False
    '''
    isok = False
    try:
        cursor = conn.cursor()
        # 更新元数据
        for k, v in meta.items():
            cursor.execute('''
                UPDATE filemeta SET value = :value
                WHERE fileinfoid = :fileinfoid AND key = :key
            ''', {'value': v, 'fileinfoid': fileinfoid, 'key': k})
        
        conn.commit()
        cursor.close()
        isok = True
    except Exception as e:
        print(e)
        conn.rollback()  # 回滚事务

    return isok



# 根据文件信息构造数据字典
def get_data_dict(filepath:str):
    '''
        根据文件信息构造数据字典
        :Args:
            - filepath: 原文件名，文件全路径，例如：'mp4/2024/12/03/17/23/00.mp4'
        :Return:
            数据字典，包含以下字段：
                {
                    'path': 'mp4目录下的文件路径',
                    'srcname': '原文件名',
                    'dstname': 'new',（可暂时为空）
                    'description': '文件介绍',(原文件名称替换'.mp4'为空)
                    'tags': '文件标签',(可暂时为空)
                    'mcurl': 'minio文件存储位置',（可暂时为空）
                    'ctime': '创建时间', （文件创建时间,例如：2024-09-03 18:30:12）
                    'mtime': '修改时间', （文件修改时间,例如：2024-09-03 18:30:12）
                    'size': '文件大小',
                    'status': '文件状态, 1-正常，0-删除...; 默认为1',
                    'note': '备注'
                }
    '''
    _fn = os.path.basename(filepath)
    ctime = os.path.getctime(filepath) # 文件创建时间
    mtime = os.path.getmtime(filepath) # 文件修改时间
    # 文件大小, 单位kb, 保留整数
    size = round(os.path.getsize(filepath)/1024)

    _description = _fn.replace('.mp4', '')
    _ctime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ctime))
    _mtime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(mtime))
    _data = {
        'path': os.path.dirname(filepath),
        'srcname': _fn,
        'dstname': 'new',
        'description': _description,
        'mcurl': 'no',
        'ctime': _ctime,
        'mtime': _mtime,
        'size': size,
        'status': 1,
        'note': ''
    }
    return _data

# 文件名处理
def filenameact(fn:str):
    '''
        文件名处理, 处理规则：
            - 去掉文件名中的特殊字符
            - 将文件名中的空格替换为'#'
            - 将文件名称中的'@'和'.mp4'之间的字符替换为'_'
            - 将文件名称中的'@'替换为空
            - 将文件名中的网友账户名替换为'网友'
        :Args:
            - fn: 文件名
        :Return:
            处理后的文件名
    '''
    pass

# 获取处理tags
def gettags(srcname:str):
    '''
        获取处理tags
        :Args:
            - srcname: 原文件名
        :Return:
            处理后的tags
    '''
    pass

# 重命名mp4目录下面的所有文件
def renameallmp4file():
    '''
        重命名mp4目录下面的所有文件
        :Args: 无
        :Return: 无
    '''
    pass

